#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>

#include "mpHttpResponseTranslation.h"
#include "mpStringUtils.h"
#include "mpHttpParams.h"
#include "mpLog.h"

namespace MP{
namespace HTTP{
namespace INTERNAL{


void HttpResponseTranslation::reset(HttpResponseMessage* httpResponseMessage,
                                    const std::string& http_method){

    _httpResponseMessage = httpResponseMessage;

    _tmp_data.clear();
    _is_parsed_http_statu_line = false;     //是否已完成Http Status Line解析
    _is_parsed_http_header = false;         //是否已完成Http Header解析
    _is_parsed_finished = false;            //是否已全部解析完成
    _is_has_content_length = false;         //Http Header中是否包含Content-Length信息
    _is_chunked = false;                    //数据是否以一系列分块的形式进行发送
    _is_chunked_complete = false;           //数据分块发送完成

    //是否Http响应中Body为空（当HttpMethod=Head的时候）
    _is_response_body_none = (http_method == "HEAD");

    _next_block_chunk_size = INVALID_SIZE;  //chunked情况下，下一数据块的大小
    _header_content_length = INVALID_SIZE;  //Http Header中标识的Content-Length值
    _header_size = 0;                       //HTTP响应头部内容的大小（Http Status Line + Http Header）
    _response_content_size = 0;             //HTTP Content内容的大小
}

bool HttpResponseTranslation::finished() const{
    return _is_parsed_finished;
}

bool HttpResponseTranslation::is_parsed_http_header() const{
    return _is_parsed_http_header;
}
std::size_t HttpResponseTranslation::getContentLength() const{
    return _header_content_length;
}
std::size_t HttpResponseTranslation::getContentReadLength() const{
    return _response_content_size;
}

bool HttpResponseTranslation::checkContentReadIsComplete() const{
    if(_is_response_body_none){
        return true;
    }
    else{
        if(_is_chunked){
            return _is_chunked_complete;
        }
        else{
            return _response_content_size >= _header_content_length;
        }
    }
}

//解析数据：如果返回真，则表示解析成功；如果返回假，则表示解析失败
bool HttpResponseTranslation::parse(const char* data, std::size_t length){

    if(_is_parsed_http_header){
        return parseResponseContent(data,length);
    }

    //解析HTTP响应头部内容
    if(!parseResponseHeader(data,length)){
        return false;
    }

    //如果HTTP响应头部内容仍未解析完成，则返回真继续解析
    if(!_is_parsed_http_header){
        return true;
    }


    //初始化Http Response Content,准备开始写入

    //如果 HttpResponseContent 是 HttpResponseFileContent 并且 HTTP 状态不为200，则不开启写入。

    if(_httpResponseMessage->getHttpResponseContent()->isHttpResponseFileContent()
            && _httpResponseMessage->getResponseCode() != 200)
    {
        MPLOG_ERROR << "http 200 status code is not returned when requesting to download a file. "
                    << "program will not be called beginReadData for cancel the file writing";
    }
    else{
        _httpResponseMessage->getHttpResponseContent()->beginReadData();
    }

    //处理解析HTTP响应头部时剩余的部分数据
    return parseResponseContent("", 0);

}

bool HttpResponseTranslation::parseResponseHeader(const char* data, std::size_t length){

    _tmp_data.append(data,length);

    bool result = true;
    std::size_t off = 0;
    std::string line;
    while(result && getNextLine(line,off)){

        off = off + line.size() + 2;

        if (line.empty()) {
            _is_parsed_http_header = true;

#if defined(MAPLE_MODE_DEBUGGING)
            MPLOG_INFO << "next, read response http content.";
#endif
            break;
        }

        if(!_is_parsed_http_statu_line){
            _is_parsed_http_statu_line = true;

            result = parseResponseStatusLine(line);

            //KEEP_ALIVE (HTTP VERSION 如果是1.0 则Connection 默认 close；否则默认Keepalive)
            //参考：https://www.cnblogs.com/cmt/p/iis-http-keep-alive.html
            if(_httpResponseMessage->isHttpVersion_1_0()){
                _httpResponseMessage->getHttpResponseHeaders().setConnectionKeepalive(false);
            }
            else{
                _httpResponseMessage->getHttpResponseHeaders().setConnectionKeepalive(true);
            }
        }
        else{
            result = parseResponseHeaderLine(line);
        }
    }

    if(_tmp_data.size() >= off){
        _header_size += off;
        _tmp_data.erase(0, off);
    }

    return result;
}

bool HttpResponseTranslation::parseResponseStatusLine(const std::string& line){

    //strStatusLine example ： HTTP/1.1 200 OK
    std::vector<std::string> parts;
    MP::StringUtils::splitString(line," ",parts);

    if(parts.size() < 2){
        MPLOG_ERROR << "http response status line [ " << line << "] parsing failed , not in the expected format.";
        return false;
    }

    std::string http_version = parts[0];
    std::string status_message = "";
    if(parts.size() > 2){
        status_message = parts[2];
    }

    unsigned int status_code = 500;
    try
    {
        status_code = std::stoi(parts[1]);
    }
    catch (const std::exception&) {
        MPLOG_ERROR << "http response status code [ " << parts[1] << "] parsing failed.";
        return false;
    }

    if(!MP::StringUtils::stringStartsWith(http_version,"HTTP/1.")){
        MPLOG_ERROR << "http response http version [ " << http_version << "] not in the expected .";
        return false;
    }

    _httpResponseMessage->setReadStatus(http_version,status_code,status_message);

#if defined(MAPLE_MODE_DEBUGGING)
    MPLOG_INFO << "read response http statusLine.";
    MPLOG_INFO << "--http_version : " << http_version;
    MPLOG_INFO << "--status_code : " << status_code;
    MPLOG_INFO << "--status_message : " << status_message;

    MPLOG_INFO << "next, read response http header.";
#endif

    return true;
}

bool HttpResponseTranslation::parseResponseHeaderLine(const std::string& line){

#if defined(MAPLE_MODE_DEBUGGING)
    MPLOG_INFO << "--" << line;
#endif

    std::vector<std::string> vec;
    MP::StringUtils::splitString(line,":",vec);

    if(vec.size() == 2){
        std::string key = MP::StringUtils::trim_copy(vec[0]);
        std::string val = MP::StringUtils::trim_copy(vec[1]);
        bool n = false;
        //boost::iequals 比较时，不区分大小写
        if (boost::iequals(key, MP::HTTP::HK_CONTENT_LENGTH)) {
            _is_has_content_length = true;
            try
            {
                _header_content_length = boost::lexical_cast<std::size_t>(val) ;
            }
            catch (boost::bad_lexical_cast &)
            {
                MPLOG_ERROR << "HttpResponseTranslation Get Http Content Length Fail." << val;
            }
            n = true;
        }

        if (boost::iequals(key, MP::HTTP::HK_CONTENT_TYPE)) {
            _httpResponseMessage->getHttpResponseContent()->setContentType(val);
            n = true;
        }

        //KEEP_ALIVE (如果返回的是close则设置未close)
        if (boost::iequals(key, MP::HTTP::HK_CONNECTION)) {
            if (boost::iequals(val, MP::HTTP::HK_CONNECTION_CLOSE)) {
                _httpResponseMessage->getHttpResponseHeaders().setConnectionKeepalive(false);
            }
            n = true;
        }

        //检查数据是否以一系列分块的形式进行发送
        if (boost::iequals(key, MP::HTTP::HK_TRANSFER_ENCODING)) {
            if (boost::iequals(val, MP::HTTP::HK_TRANSFER_ENCODING_CHUNKED)) {
                _is_chunked = true;
            }
        }

        if(!n){
            _httpResponseMessage->getHttpResponseHeaders().addHeader(key,val);
        }
    }

    return true;

}

bool HttpResponseTranslation::parseResponseContent(const char* data, std::size_t length){

    if(_is_response_body_none){
        return parseComplete();
    }
    else{
        if(_is_chunked){
            return parseChunkedContent(data,length);
        }
        else{
            return parseIdentityContent(data,length);
        }
    }
}


bool HttpResponseTranslation::parseIdentityContent(const char* data, std::size_t length){

    //如果HttpHeader中未设置Content Length，则认为没有Response Content，因此直接返回
    //如果是Http请求方法为Head，那么则直接返回
    if(!_is_has_content_length){
        return parseComplete();
    }

    //如果_header_content_length仍未默认的无效值，则认为解析Content Length失败，则返回false
    if(_header_content_length == INVALID_SIZE){
        return false;
    }

    //处理解析HTTP响应头部时剩余的部分数据
    if(!_tmp_data.empty()){
        _httpResponseMessage->getHttpResponseContent()->onReadDataSome(_tmp_data.c_str(), _tmp_data.size());
        _response_content_size += _tmp_data.size();
        _tmp_data.clear();
    }

    //写入Http Response Content
    if(length > 0){
        _httpResponseMessage->getHttpResponseContent()->onReadDataSome(data,length);
        _response_content_size += length;
    }

    //检查数据是否读取完成
    if(_response_content_size >= _header_content_length){
        return parseComplete();
    }

    return true;

}

bool HttpResponseTranslation::parseChunkedContent(const char* data, std::size_t length){

    if(length > 0){
        _tmp_data.append(data, length);
    }

    bool result = true;
    while(true){

        //数据为空则继续读取数据
        if(_tmp_data.empty()){
            break;
        }

        //如果未设置_next_block_chunk_size，则解析获取值
        if(_next_block_chunk_size == INVALID_SIZE){
            std::string line;
            if(!getNextChunkedSizeLine(line)){
                //剩余数据不足一行，则跳出继续读取
                break;
            }

            if(!parseChunkedSize(line)){
                result =  false;
                break;
            }
        }

        if(_next_block_chunk_size == 0){
            _is_chunked_complete = true;
            result = parseComplete();
            break;
        }

        //_tmp_data已全部包含本block chunk的所有数据
        if(_next_block_chunk_size + 2 <= _tmp_data.size()){
            //写入数据
            _httpResponseMessage->getHttpResponseContent()->onReadDataSome(_tmp_data.c_str(),_next_block_chunk_size);
            //写入大小
            _response_content_size += _next_block_chunk_size;
            //裁剪_tmp_data
            _tmp_data.erase(0, _next_block_chunk_size + 2);
            //重置_next_block_chunk_size，准备读取下一block
            _next_block_chunk_size = INVALID_SIZE;
            //继续下一次循环
            continue;
        }
        else{
            //数据不足，继续读取
            break;
        }
    }

    return result;
}


bool HttpResponseTranslation::parseComplete(){
    _is_parsed_finished = true;
    _httpResponseMessage
            ->getHttpResponseContent()
            ->setContentLength(_response_content_size);
    _httpResponseMessage->getHttpResponseContent()->endReadData();

#if defined(MAPLE_MODE_DEBUGGING)
    MPLOG_INFO << "parse complete , temp variable : " << _tmp_data;
#endif

    return true;
}


bool HttpResponseTranslation::parseChunkedSize(const std::string& line){

#if defined(MAPLE_MODE_DEBUGGING)
    MPLOG_INFO << "parse chunked size line :" << line;
#endif

    std::string tmp = MP::StringUtils::trim_copy(line);
    bool result = true;
    try {
        _next_block_chunk_size = static_cast<std::size_t>(std::stoul(tmp,0, 16));

#if defined(MAPLE_MODE_DEBUGGING)
        MPLOG_INFO << "chunked size = " << _next_block_chunk_size;
#endif

    }
    catch (const std::exception& err)
    {
#if defined(MAPLE_MODE_DEBUGGING)
        MPLOG_INFO << "chunked size parse err ." << err.what();
#endif
        result = false;
    }
    catch (...)
    {
#if defined(MAPLE_MODE_DEBUGGING)
        MPLOG_INFO << "chunked size parse err ." << line;
#endif
        result = false;
    }
    return result;
}

bool HttpResponseTranslation::getNextLine(std::string& line,
                                          std::size_t off){

    std::size_t pos = _tmp_data.find(MP::HTTP::CRLF, off);
    if (pos == std::string::npos) {
        return false;
    }

    std::size_t count = pos - off;
    if(count > 0){
        line = _tmp_data.substr(off, count);
    }
    else{
        line.clear();
    }

    return true;
}

bool HttpResponseTranslation::getNextChunkedSizeLine(std::string& line){

    std::size_t pos = _tmp_data.find(MP::HTTP::CRLF, 0);
    if (pos == std::string::npos) {
        return false;
    }

    if(pos > 0){
        line = _tmp_data.substr(0, pos);
        _tmp_data.erase(0, pos + 2);
    }

    return true;
}


}   //INTERNAL
}   //HTTP
}   //MP
